import nunjucks from 'nunjucks';
import fs from 'fs';
import path from 'path';
import log from 'fancy-log';
import chalk from 'chalk';
import { OptimizedError, OptimizedSvg } from 'svgo';

import { svgOptimize } from './svgo';
import { DefaultTemplateRenderModel, SVGFileModel } from './types';
import { normalizeContent, normalizeName } from './svg-normalize';

function getSVGFiles(dir: string): string[] {
    if (!fs.existsSync(dir)) {
        return [];
    }

    return fs
        .readdirSync(dir)
        .map((file) => {
            const absolutePath = path.join(dir, file);

            // recall this when is directory
            if (fs.lstatSync(absolutePath).isDirectory()) {
                return getSVGFiles(absolutePath);
            }

            // return null when not end with svg
            if (!absolutePath.endsWith('.svg')) {
                return null;
            }

            return absolutePath;
        })
        ?.filter(Boolean)
        ?.flatMap((path) => path);
}

function convertToSVGFileModel(filePath: string, content: string | Buffer): Promise<SVGFileModel> {
    return new Promise<SVGFileModel>((reslove, reject) => {
        const result = svgOptimize(content);

        if (!!result?.error) {
            reject(result as OptimizedError);
            return;
        }

        reslove({
            name: path.basename(filePath, '.svg'),
            content: result as OptimizedSvg,
        });
    });
}

function convertSVGToTSXAsync(templateContent: string, svgPath: string, outputPath: string) {
    return new Promise((reslove, reject) => {
        convertToSVGFileModel(svgPath, fs.readFileSync(svgPath))
            .then((svgFileModel) => {
                const renderModel: DefaultTemplateRenderModel = {
                    icon: {
                        name: normalizeName(svgFileModel.name),
                        content: normalizeContent(svgFileModel.content?.data),
                    },
                    comment: 'Generated by svg-to-tsx -- pls do not modify this file manually',
                };

                const iconName = `Icon${renderModel?.icon?.name}.tsx`;
                const iconOutputPath = path.isAbsolute(outputPath)
                    ? outputPath
                    : path.join(process.cwd(), outputPath);
                const iconFullOutputPath = path.join(iconOutputPath, iconName);

                const tsxString = nunjucks.renderString(templateContent, renderModel);

                log(chalk.green('Ready to write SVG Icon component to:', iconOutputPath)); // eslint-disable-line no-console

                if (!fs.existsSync(iconOutputPath)) {
                    fs.mkdirSync(iconOutputPath, { recursive: true });
                }

                fs.writeFileSync(iconFullOutputPath, tsxString);

                log(chalk.green('Generated SVG Icon component to:', iconFullOutputPath)); // eslint-disable-line no-console
                log(chalk.green(`You can use this by <Icon${renderModel?.icon?.name} />`)); // eslint-disable-line no-console

                reslove(true);
            })
            .catch((err) => {
                log(chalk.red('Convert SVG To TSX Error:', err));
                reject(err);
            });
    });
}

export { getSVGFiles, convertToSVGFileModel, convertSVGToTSXAsync };
